<script setup lang="ts">
import { handleLabel, formatInput, toPx, isFunction } from '@/utils';
import { cloneDeep } from 'lodash-es';
import { Result } from '@/service/request/type';
import { Message } from '@/instance';
import { LabelFn } from './type';

const props = defineProps<{
    width?: string;
    column?: boolean;
    editConfig: PageConfig;
    updateFn: (data: any) => Promise<Result<any>> | void;
    tableRef?: TableRef;
    handleSubmitData?: (data: any) => any;
    title?: string;
}>();

const emit = defineEmits(['open', 'selectChange']);
const modelTitle = computed(() => (check.value ? '查看' : '编辑'));
const okText = computed(() => (check.value ? '关闭' : '确定'));

// 表单数据
const formData = ref<anyObj>({});

/**
 * 输入获取焦点，做出相对于校验
 */
const {
    popoverVisible,
    popoverErrMsg,
    handleInput,
    handleFocus,
    handleValidFieldPass,
    setValidErrorVisible,
    showErrorPopover,
    hideErrorPopover
} = useValid({
    position: 'left',
    formConfig: props.editConfig.items,
    formFields: formData
});

const { visible, loading, modalOk, handleCancel } = useModal({
    validFn: handleValidFieldPass,
    data: formData
});

// 点击确定
const submit = () => {
    if (check.value) {
        visible.value = false;
        return;
    }
    modalOk(handleSubmit);
};

const formDataFn = computed(() => {
    return (cb: LabelFn) => cb(formData.value);
});

const handleSubmit = async () => {
    try {
        let submitData = formData.value;

        if (props.handleSubmitData) {
            submitData = props.handleSubmitData(submitData);
        }

        const res = await props.updateFn(submitData);

        if (res) {
            Message.success('操作成功！');
            props.tableRef?.getData?.();
            return res;
        }
    } catch (error) {
        console.log(error);
    }
};

/**
 * 打开弹框
 */
const check = ref<undefined | boolean>();
const open = (row: anyObj, isCheck?: boolean) => {
    check.value = isCheck;
    visible.value = true;
    setFormData(row);
    emit('open', formData.value);
};

/**
 * 关闭弹框
 */
const close = () => (visible.value = false);

const getLabel = (label?: string | LabelFn) => {
    return isFunction(label) ? formDataFn.value(label as LabelFn) : (label as string);
};

const setFormData = (row: anyObj) => {
    formData.value = cloneDeep(row); // cloneDeep lodash 的clone
};

/**
 * 设置编辑表单某项字段值
 */
const setFormDataToKey = (key: string, value: any) => {
    formData.value[key] = value;
};

/**
 * 处理引导提示
 */
type TipMsg = Pick<OtherConfig, 'tipMsg'>;
type TipMsgKey = keyof TipMsg;
type TipMsgValue = TipMsg[TipMsgKey];
const handleTipMsg = (tipMsg?: TipMsgValue) => {
    return isFunction(tipMsg) ? (tipMsg as any)(formData.value) : tipMsg;
};

defineExpose({
    submit,
    open,
    close,
    check,
    setFormData,
    formData,
    setFormDataToKey
});
</script>
<template>
    <q-modal
        v-model:visible="visible"
        :title="modelTitle"
        :close-cancel="true"
        :width="width || '1000px'"
        :confirm-loading="loading"
        :hide-cancel-btn="check"
        :ok-text="okText"
        @cancel="handleCancel"
        @ok="submit"
    >
        <div :class="['m-edit-form', { 'is-column': column }]">
            <div
                v-for="{
                    itemType,
                    columnProps,
                    validProps,
                    validRules,
                    validFormatType,
                    otherConfig,
                    slotName,
                    modelKey,
                    elSelectProps,
                    elDatePickerProps,
                    elInputNumberProps,
                    elInputProps,
                    elTimePickerProps,
                    elCheckboxProps,
                    elRadioProps
                } in editConfig.items"
                :key="modelKey"
                class="m-edit-form__main form-common"
            >
                <label :style="{ width: toPx(editConfig?.labelWidth || '110px') }">
                    <span v-if="validProps?.required">*</span>
                    {{ getLabel(columnProps?.label) }}

                    <base-tooltip
                        :tip="otherConfig?.tip"
                        :tip-msg="handleTipMsg(otherConfig?.tipMsg)"
                    />
                    :
                </label>
                <q-form-item
                    v-bind="columnProps"
                    :id="validProps!.id!"
                    :label="handleLabel(getLabel(columnProps?.label))"
                    class="m-edit-form__item"
                >
                    <template v-if="slotName">
                        <slot
                            :name="slotName"
                            :row="formData"
                            :item="{ columnProps, modelKey, validProps, validRules }"
                            :validFn="{
                                handleFocus,
                                handleInput,
                                setValidErrorVisible
                            }"
                        ></slot>
                    </template>
                    <template v-else>
                        <el-input
                            v-if="itemType === 'text'"
                            v-model.trim="formData[modelKey!]"
                            :disabled="check"
                            :prop="modelKey"
                            v-bind="elInputProps"
                            @keyup="
                                (e: any) => {
                                    formData[modelKey!] = formatInput(
                                        formData,
                                        modelKey!,
                                        validFormatType,
                                        {
                                            showErrorPopover: (msg: string) => {
                                                showErrorPopover(e, msg);
                                            },
                                            hideErrorPopover
                                        }
                                    );
                                    handleInput(e, formData, {
                                        config: {
                                            modelKey,
                                            columnProps,
                                            validProps,
                                            validRules
                                        }
                                    });
                                }
                            "
                            @focus="
                                (e: any) =>
                                    handleFocus(e, formData, {
                                        config: {
                                            modelKey,
                                            columnProps,
                                            validProps,
                                            validRules
                                        }
                                    })
                            "
                            @blur="
                                (e: any) => {
                                    formData[modelKey!] = formatInput(
                                        formData,
                                        modelKey!,
                                        validFormatType,
                                        {
                                            showErrorPopover: (msg: string) => {
                                                showErrorPopover(e, msg);
                                            },
                                            hideErrorPopover
                                        }
                                    );
                                    popoverVisible = false;
                                }
                            "
                        />
                        <el-input-number
                            v-else-if="itemType === 'number'"
                            v-model.trim="formData[modelKey!]"
                            :disabled="check"
                            :prop="modelKey"
                            :precision="0"
                            :min="1"
                            v-bind="elInputNumberProps"
                        />
                        <el-date-picker
                            v-else-if="itemType === 'date'"
                            v-model="formData[modelKey!]"
                            :disabled="check"
                            clearable
                            value-format="YYYY-MM-DD"
                            :prop="modelKey"
                            v-bind="elDatePickerProps"
                        />
                        <el-time-picker
                            v-else-if="itemType === 'time'"
                            v-model="formData[modelKey!]"
                            :disabled="check"
                            clearable
                            value-format="YYYY-MM-DD hh:mm:ss"
                            :prop="modelKey"
                            v-bind="elTimePickerProps"
                        />
                        <el-select
                            v-else-if="itemType === 'select'"
                            v-model="formData[modelKey!]"
                            :disabled="check"
                            clearable
                            fit-input-width
                            v-bind="elSelectProps"
                            @change="emit('selectChange', { modelKey }, formData)"
                        >
                            <el-option
                                v-for="(item, index) in elSelectProps?.options"
                                :key="
                                    index +
                                    ((elSelectProps?.optionLabelKey &&
                                        item[elSelectProps.optionLabelKey]) ||
                                        item.label ||
                                        item)
                                "
                                :label="
                                    elSelectProps?.optionLabelKey
                                        ? item[elSelectProps.optionLabelKey]
                                        : item.label || item
                                "
                                :value="
                                    elSelectProps?.optionValueKey
                                        ? item[elSelectProps.optionValueKey]
                                        : item.value || item
                                "
                            ></el-option>
                        </el-select>
                        <el-radio-group
                            v-else-if="itemType === 'radio'"
                            v-model="formData[modelKey!]"
                        >
                            <el-radio
                                v-for="option in elRadioProps?.options"
                                :key="option.value"
                                :label="option.value"
                                :value="option.value"
                                :disabled="check"
                                v-bind="elRadioProps"
                            >
                                {{ option.label }}
                            </el-radio>
                        </el-radio-group>
                        <el-checkbox-group
                            v-else-if="itemType === 'checkbox'"
                            v-model="formData[modelKey!]"
                        >
                            <el-checkbox
                                v-for="option in elRadioProps?.options"
                                :key="option.value"
                                :label="option.value"
                                :value="option.value"
                                :disabled="check"
                                name="type"
                                v-bind="elCheckboxProps"
                            >
                                {{ option.label }}
                            </el-checkbox>
                        </el-checkbox-group>
                    </template>
                </q-form-item>
            </div>
        </div>

        <!-- 校验提示框 -->
        <q-valid-popover
            :popover-visible="popoverVisible"
            :popover-err-msg="popoverErrMsg"
            position="left"
        />
    </q-modal>
</template>

<style scoped lang="scss">
@include b(m-edit-form) {
    display: grid;
    grid-template-columns: repeat(2, 1fr);

    @include when(column) {
        grid-template-columns: 1fr;
    }

    @include e(main) {
        @include flex(center, flex-start);

        margin: 8px 32px 16px 0;

        & > label {
            @include flex(flex-end);

            width: 100px;
        }
    }

    @include e(item) {
        position: relative;
        flex: 1;

        :deep() {
            .el-select {
                display: block;
            }
        }
    }
}
</style>
